use std::time::Duration;
use proto::{codec::decode_u16, new_buf, HEAD, MIN_LEN};
use tokio::{io::{AsyncReadExt, BufReader}, net::tcp::OwnedReadHalf, time::timeout};
use crate::AppErr;
use super::frame::Frame;



pub struct ConnReader {
    rx: BufReader<OwnedReadHalf>
}

impl ConnReader {

    pub fn new(rx: OwnedReadHalf) -> ConnReader {
        ConnReader { 
            rx: BufReader::new(rx)
        }
    }

    pub async fn read_with_timeout(&mut self, duration: Duration) -> Result<Frame, AppErr> {
        timeout(duration, self.read()).await.map_err(|_| AppErr::Timeout("read timeout"))?
    }

    async fn read(&mut self) -> Result<Frame, AppErr> {
        let mut head_buf: [u8; 4] = [0; 4];
        self.rx.read_exact(&mut head_buf).await?;

        let head = decode_u16(&head_buf);
        if head != HEAD {
            return Err(AppErr::Proto("head invalid"));
        }
        
        let len = decode_u16(&head_buf[2..]) as usize;
        if len < MIN_LEN {
            return Err(AppErr::Proto("len invalid"));
        }

        let mut body = new_buf(len - 4);
        self.rx.read_exact(&mut body).await?;

        Ok( Frame::new(body) )
    }
}



